package com.example.utils.util.JwtUtil;

import com.auth0.jwt.JWT;
import com.auth0.jwt.JWTVerifier;
import com.auth0.jwt.algorithms.Algorithm;
import com.auth0.jwt.exceptions.JWTVerificationException;
import com.auth0.jwt.interfaces.Claim;
import com.auth0.jwt.interfaces.DecodedJWT;

import java.util.Calendar;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;

/**
 * TODO   和别的项目进行对接的时候对面携带jwt生成的token值，我们需要进行解析验证，所以有了这个jwt的Demo
 *
 * @ClassName JWTTest
 * @Author xiaojiang
 * @Date 2021/10/20 下午 17:16
 */
public class JWTTest {

    /**
     * SALT：盐，或称密钥。加密使用，需要服务端保管好
     */
    private static final String SALT = "e490354df5c9a23be01e3c1d4490354df5c9a23be01e3c1d40c79d5d52fe992dbee490354df5c9a20c79d5d52fe992dbee490354df5c9a23be01e3c1d40c79d5d52fe992dbe";


    /**
     * 创建 Token
//     * @param userName 用户名，用作于接口过滤。可根据具体的业务进行设置
     * @return Token 字符串
     */
//    public static String createToken(String userName){
    public static String createToken(){
        // 签发时间
        Date issueDate = new Date();

        // 过期时间
        Calendar nowTime = Calendar.getInstance();
        nowTime.add(Calendar.MINUTE, 10); // 8 小时过期  480
        Date expireDate = nowTime.getTime();

        Map<String, Object> headerMap = new HashMap<>();
        headerMap.put("alg", "HMAC256"); // 声明算法
        headerMap.put("typ", "JWT"); // 声明类型

        return JWT.create()
                .withHeader(headerMap)  // header段，带有算法信息和类型信息
                .withExpiresAt(expireDate) // payload段，设置过期时间
                .withIssuedAt(issueDate) //payload段，设置签发时间
                .withIssuer("HUAWEI") // payload段，设置签发者
                .withJWTId("c749a8dc-efe8-4feb-9052-df4bd3e293db")   // 编号
//                .withClaim("aud","[\"ausf116\"]")  // 接收者
                .withClaim("scope","nausf-auth")   // 自定义的范围
                .withClaim("sub", "ae3f5de7-b35a-4f5c-a653-38822fa7812c") // payload段，自定义信息
                .sign(Algorithm.HMAC256(SALT)); // signature段，进行加盐加密
    }

    /**
     * 验证 Token
     * @param token token 字符串
     * @return 这里我选择取回 payload 段的信息，因为里面有自定义信息，我可以拿来处理业务逻辑
     */
    public static Map<String, Claim> verifyToken(String token) {
        try {
            if(token != null){
                // 解密也需要该 salt，所以它很重要，不要泄露
                JWTVerifier verifier = JWT.require(Algorithm.HMAC256(SALT)).build();
                DecodedJWT jwt = verifier.verify(token);
                return jwt.getClaims();
                /*if(SystemConstant.ISSUER.equals(jwt.getIssuer())){
                    return jwt.getClaims();
                }*/
            }
        } catch (IllegalArgumentException e) {
            e.printStackTrace();
            System.out.println("----");
        } catch (JWTVerificationException e) {
            e.printStackTrace();
            System.out.println("=====");
        }
        return null;
    }

    /**
     * 模拟接口认证
     */
    public static void main(String[] args) {

        String token = createToken();
        System.out.println("token : " + token);
       /* String[] parts = token.split("\\.");
        if (parts.length == 2 && token.endsWith(".")) {
            //Tokens with alg='none' have empty String as Signature.
            parts = new String[]{parts[0], parts[1], ""};
        }
        if (parts.length != 3) {
            throw new JWTDecodeException(String.format("The token was expected to have 3 parts, but got %s.", parts.length));
        }
        System.out.println(new String (Base64.decodeBase64(parts[0])));
        System.out.println(new String (Base64.decodeBase64(parts[1])));*/
//         1. 取前端带过来的 token 信息。现在假设这就是前端带上来的数据
//        String token = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJhdWQiOlsiYXVzZjExNiJdLCJleHAiOjYwLCJzY29wZSI6Im5hdXNmLWF1dGgiLCJzdWIiOiJhZTNmNWRlNy1iMzVhLTRmNWMtYTY1My0zODgyMmZhNzgxMmMifQ.lvh6By5fQoEU86If9jjkIqGAhRCi1Nnw57-kFgnESgY";
//        String token = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiJhZTNmNWRlNy1iMzVhLTRmNWMtYTY1My0zODgyMmZhNzgxMmMiLCJzY29wZSI6Im5hdXNmLWF1dGgiLCJpc3MiOiJIVUFXRUkiLCJleHAiOjE2MzQ3MjUzMjEsImlhdCI6MTYzNDcyNDcyMSwianRpIjoiYzc0OWE4ZGMtZWZlOC00ZmViLTkwNTItZGY0YmQzZTI5M2RiIn0.4eKxWy6BPeAACoACvnxe_3xXG40l1EczemJj6Jko9sc";
        // 2. 验证 Token
        boolean result = false;
        // 取得 payload 段的信息
        Map<String, Claim> claimMap = JWTTest.verifyToken(token);
        System.out.println("claimMap == " + claimMap);
        if(claimMap != null){
            // 取出里面的用户名
            try {
                String sub = claimMap.get("sub").asString();
                System.out.println("sub : " + sub);
                String scope = claimMap.get("scope").asString();
                System.out.println("scope : " + scope);

                String iss = claimMap.get("iss").asString();
                System.out.println("iss : " + iss);
                String jwt_id = claimMap.get("jti").asString();
                System.out.println("jti : " + jwt_id);
                // 检查该用户名是否存在，存在就放行，不存在就返回指定的信息
                result = true;
            } catch (Exception e) {
                e.printStackTrace();
            }

        }

        // 3. 处理结果
        if(result){
            // 放行
            System.out.println("放行");
        }else {
            // 返回指定错误信息
            // 放行
            System.out.println("bu放行");
        }
    }

}
